diff --git a/.gitignore b/.gitignore
index c9b9f6b..3e92faf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
/node_modules/
-.DS_STORE
\ No newline at end of file
+.DS_STORE
+.idea/
diff --git a/circle.yml b/circle.yml
index af7cd4f..0d3c95e 100644
--- a/circle.yml
+++ b/circle.yml
@@ -1,6 +1,7 @@
-version: 2
+version: 2.1
+
jobs:
- build:
+ php-tests:
docker:
- image: php:7
working_directory: ~/build
@@ -29,3 +30,22 @@ jobs:
- store_test_results:
path: "./tmp/"
+
+ javascript-tests:
+ docker:
+ - image: cimg/node:20.19
+ working_directory: ~/build
+ steps:
+ - checkout
+ - run:
+ name: "Run Calendar Parameter Tests"
+ command: npm run test:calendar
+ - run:
+ name: "Run Card Image Widget Tests"
+ command: npm run test:card-images
+
+workflows:
+ tests:
+ jobs:
+ - php-tests
+ - javascript-tests
diff --git a/package.json b/package.json
index 0a8ed74..c75d112 100644
--- a/package.json
+++ b/package.json
@@ -10,6 +10,8 @@
"format:js": "wp-scripts format-js",
"lint:css": "wp-scripts lint-style",
"lint:js": "wp-scripts lint-js",
+ "test:card-images": "node tests/card-image-widgets.test.js",
+ "test:calendar": "node tests/calendar-params.test.js",
"start": "wp-scripts start showpass-block-src/index.js --output-path=plugin/build-blocks",
"packages-update": "wp-scripts packages-update"
},
diff --git a/plugin/inc/default-grid.php b/plugin/inc/default-grid.php
index 451c12e..5786791 100644
--- a/plugin/inc/default-grid.php
+++ b/plugin/inc/default-grid.php
@@ -24,6 +24,7 @@
foreach ($events as $key => $event) {
// default event link does nothing
$event_href = 'javascript:void(0);';
+ $image_opens_widget = false;
if (isset($event['external_link'])) {
$event_href = $event['external_link'];
}
@@ -35,13 +36,22 @@
*/
if (isset($detail_page)) {
$event_href = sprintf('/%s/?slug=%s', $detail_page, $event['slug']);
+ } else {
+ $image_opens_widget = true;
}
}
?>
\ No newline at end of file
+
diff --git a/plugin/inc/default-list.php b/plugin/inc/default-list.php
index 6d37ad2..1001040 100644
--- a/plugin/inc/default-list.php
+++ b/plugin/inc/default-list.php
@@ -25,28 +25,37 @@
$event_href = sprintf('/%s/?slug=%s', $detail_page, $event['slug']);
}
}
+ $image_opens_widget = !isset($event['external_link'])
+ && !isset($detail_page)
+ && !showpass_ticket_sold_out($event);
?>
\ No newline at end of file
+
diff --git a/plugin/inc/default-membership-grid.php b/plugin/inc/default-membership-grid.php
index ee7e32a..040e3a3 100644
--- a/plugin/inc/default-membership-grid.php
+++ b/plugin/inc/default-membership-grid.php
@@ -27,7 +27,10 @@
\ No newline at end of file
+
diff --git a/plugin/js/showpass-calendar-params.js b/plugin/js/showpass-calendar-params.js
new file mode 100644
index 0000000..9db09fb
--- /dev/null
+++ b/plugin/js/showpass-calendar-params.js
@@ -0,0 +1,99 @@
+(function (root) {
+ "use strict";
+
+ function getAttribute(element, name) {
+ if (!element || typeof element.getAttribute !== "function") {
+ return "";
+ }
+
+ var value = element.getAttribute(name);
+ return typeof value === "string" ? value.trim() : "";
+ }
+
+ function parsePositiveInteger(value) {
+ if (!/^[1-9][0-9]*$/.test(value)) {
+ return undefined;
+ }
+
+ var parsed = Number(value);
+ return parsed <= 9007199254740991 ? parsed : undefined;
+ }
+
+ function parseBoolean(value) {
+ if (value === "true") {
+ return true;
+ }
+ if (value === "false") {
+ return false;
+ }
+
+ return undefined;
+ }
+
+ function parseSpecialEvent(value) {
+ var keys = value
+ .split(",")
+ .map(function (key) {
+ return key.trim();
+ })
+ .filter(function (key) {
+ return key !== "";
+ });
+
+ if (keys.length === 0) {
+ return undefined;
+ }
+
+ return keys.length === 1 ? keys[0] : keys;
+ }
+
+ function fromElement(element) {
+ var params = {};
+ var calendarOpenState = getAttribute(element, "data-calendar-open-state");
+ var calendarDate = getAttribute(element, "data-calendar-date");
+ var calendarTimeslot = getAttribute(element, "data-calendar-timeslot");
+ var calendarSpecialEvent = parseSpecialEvent(
+ getAttribute(element, "data-calendar-special-event")
+ );
+ var displayPricePatronTypeId = parsePositiveInteger(
+ getAttribute(element, "data-display-price-patron-type-id")
+ );
+ var hidePrice = parseBoolean(getAttribute(element, "data-hide-price"));
+ var highlightMultiDayEventsOnStartDateOnly = parseBoolean(
+ getAttribute(
+ element,
+ "data-highlight-multi-day-events-on-start-date-only"
+ )
+ );
+
+ if (calendarOpenState === "calendar" || calendarOpenState === "special-events") {
+ params.calendarOpenState = calendarOpenState;
+ }
+
+ if (calendarDate !== "") {
+ params.calendarDate = calendarDate;
+ }
+ if (calendarTimeslot !== "") {
+ params.calendarTimeslot = calendarTimeslot;
+ }
+ if (calendarSpecialEvent !== undefined) {
+ params.calendarSpecialEvent = calendarSpecialEvent;
+ }
+ if (displayPricePatronTypeId !== undefined) {
+ params.displayPricePatronTypeId = displayPricePatronTypeId;
+ }
+ if (hidePrice !== undefined) {
+ params.hidePrice = hidePrice;
+ }
+ if (highlightMultiDayEventsOnStartDateOnly !== undefined) {
+ params.highlightMultiDayEventsOnStartDateOnly =
+ highlightMultiDayEventsOnStartDateOnly;
+ }
+
+ return params;
+ }
+
+ root.ShowpassCalendarParams = {
+ fromElement: fromElement,
+ };
+})(window);
diff --git a/plugin/js/showpass-custom.js b/plugin/js/showpass-custom.js
index 5dccbe7..99ff6cd 100644
--- a/plugin/js/showpass-custom.js
+++ b/plugin/js/showpass-custom.js
@@ -204,6 +204,10 @@
lang: $(this).attr("data-lang"),
};
+ Object.assign(
+ params,
+ window.ShowpassCalendarParams.fromElement(this)
+ );
params["redirect-url"] = encodeURIComponent(
window.location.href
@@ -247,6 +251,12 @@
"#option_widget_color"
).val(),
};
+ Object.assign(
+ params,
+ window.ShowpassCalendarParams.fromElement(
+ embeddedCalendarWidget
+ )
+ );
if (
embeddedCalendarWidget.getAttribute("data-tags")
) {
diff --git a/plugin/readme.txt b/plugin/readme.txt
index 3e73af7..7326e52 100644
--- a/plugin/readme.txt
+++ b/plugin/readme.txt
@@ -2,7 +2,7 @@
Tags: showpass, events, tickets, sell tickets, event calendar, purchase tickets, custom event pages
Requires at least: 4.9
Tested up to: 6.8.2
-Stable tag: 4.0.8
+Stable tag: 4.0.9
Requires PHP: 5.4.45
Contributors: marcshowpass, spapril, spzachary, cgarrovillosp
@@ -14,6 +14,24 @@ List events, display event details and products. Use the Showpass purchase widge
Showpass is a full event management solution, allowing organizations and individuals to organize and execute successful events.
+== Calendar shortcode attributes ==
+
+Both `[showpass_calendar_widget]` and `[showpass_embed_calendar]` accept these optional attributes:
+
+* `display_price_patron_type_id` - a positive venue-local PatronType ID. This changes displayed prices only and never filters availability, calendar contents, or ticket choices.
+* `hide_price` - `true` or `false`. This hides calendar price text and the price-range filter without changing availability or ticket selection.
+* `calendar_date` - a venue-local date such as `2026-09-14`.
+* `calendar_timeslot` - a public timeslot key used with `calendar_date`.
+* `calendar_special_event` - one attraction special-event key, multiple comma-separated keys, or `all` to select every currently filterable special event.
+* `calendar_open_state` - `calendar` (default) or `special-events`. Opens the Special Events tab when rich special-event content is available; otherwise keeps the calendar view. This controls the view independently of special-event filtering. When combined with a date/timeslot target, the Special Events view opens first. Any configured quantity prompt still comes first.
+* `highlight_multi_day_events_on_start_date_only` - `true` or `false`. Highlights multi-day events only on their local start date.
+
+Example: `[showpass_embed_calendar calendar_date="2026-09-14" calendar_timeslot="evening" calendar_special_event="opening,closing" display_price_patron_type_id="17" hide_price="false"]`
+
+Special Events example: `[showpass_embed_calendar is_attraction="true" event_id="YOUR_ATTRACTION_ID" calendar_special_event="all" calendar_open_state="special-events"]`
+
+The new options require the corresponding calendar frontend and rebuilt SDK to be deployed before releasing this plugin update.
+
Whether you are selling tickets to your fundraiser, or an assigned seating theatre show, Showpass has the technology you need to get the job done.
Wordpress version 5.3 is required for editor blocks
@@ -55,6 +73,10 @@ Please visit our support documentation at [http://support.showpass.com](http://s
== Changelog ==
+= 4.0.9 =
+* Expose current calendar SDK options through the modal and embedded calendar shortcodes
+* Make event and membership card images open the same destination as their titles while preserving external links, detail pages, and sold-out behavior
+
= 4.0.7 =
* Force redirect-url param for Affirm support
diff --git a/plugin/showpass-wordpress-plugin-shortcode.php b/plugin/showpass-wordpress-plugin-shortcode.php
index 7f94c0e..605d60b 100644
--- a/plugin/showpass-wordpress-plugin-shortcode.php
+++ b/plugin/showpass-wordpress-plugin-shortcode.php
@@ -435,7 +435,7 @@ function showpass_display_date ($event, $small = false) {
$ends_date_element .=''
.'';
}
-
+
// Display TBD for date if set
if ($event_tbd) {
// start element
@@ -888,22 +888,22 @@ function showpass_widget_expand($atts, $content = null) {
$div = '';
} else {
@@ -1067,6 +1067,133 @@ function wpshp_cart_button($atts, $content = null) {
add_shortcode('showpass_cart_button', 'wpshp_cart_button');
+function showpass_calendar_string_value($value) {
+ if (!is_scalar($value)) {
+ return null;
+ }
+
+ $value = trim((string) $value);
+ if ($value === '') {
+ return null;
+ }
+
+ if (function_exists('sanitize_text_field')) {
+ $value = sanitize_text_field($value);
+ }
+
+ return $value === '' ? null : $value;
+}
+
+function showpass_calendar_positive_integer($value) {
+ $value = showpass_calendar_string_value($value);
+ if ($value === null || !preg_match('/^[1-9][0-9]*$/', $value)) {
+ return null;
+ }
+
+ $integer = filter_var(
+ $value,
+ FILTER_VALIDATE_INT,
+ array('options' => array('min_range' => 1))
+ );
+
+ return $integer === false ? null : $integer;
+}
+
+function showpass_calendar_boolean($value) {
+ if (is_bool($value)) {
+ return $value;
+ }
+
+ if (!is_scalar($value)) {
+ return null;
+ }
+
+ $value = strtolower(trim((string) $value));
+ if ($value === 'true' || $value === '1') {
+ return true;
+ }
+ if ($value === 'false' || $value === '0') {
+ return false;
+ }
+
+ return null;
+}
+
+function showpass_calendar_special_event($value) {
+ if (!is_scalar($value)) {
+ return null;
+ }
+
+ $keys = array();
+ foreach (explode(',', (string) $value) as $key) {
+ $key = showpass_calendar_string_value($key);
+ if ($key !== null) {
+ $keys[] = $key;
+ }
+ }
+
+ return count($keys) > 0 ? implode(',', $keys) : null;
+}
+
+function showpass_calendar_widget_data_attributes($atts) {
+ $attributes = array();
+
+ $string_attributes = array(
+ 'calendar_date' => 'data-calendar-date',
+ 'calendar_timeslot' => 'data-calendar-timeslot',
+ );
+ foreach ($string_attributes as $shortcode_attribute => $data_attribute) {
+ if (isset($atts[$shortcode_attribute])) {
+ $value = showpass_calendar_string_value($atts[$shortcode_attribute]);
+ if ($value !== null) {
+ $attributes[$data_attribute] = $value;
+ }
+ }
+ }
+
+ if (isset($atts['calendar_open_state'])) {
+ $value = showpass_calendar_string_value($atts['calendar_open_state']);
+ if (in_array($value, array('calendar', 'special-events'), true)) {
+ $attributes['data-calendar-open-state'] = $value;
+ }
+ }
+
+ if (isset($atts['calendar_special_event'])) {
+ $value = showpass_calendar_special_event($atts['calendar_special_event']);
+ if ($value !== null) {
+ $attributes['data-calendar-special-event'] = $value;
+ }
+ }
+
+ if (isset($atts['display_price_patron_type_id'])) {
+ $value = showpass_calendar_positive_integer($atts['display_price_patron_type_id']);
+ if ($value !== null) {
+ $attributes['data-display-price-patron-type-id'] = (string) $value;
+ }
+ }
+
+ if (isset($atts['hide_price'])) {
+ $value = showpass_calendar_boolean($atts['hide_price']);
+ if ($value !== null) {
+ $attributes['data-hide-price'] = $value ? 'true' : 'false';
+ }
+ }
+
+ if (isset($atts['highlight_multi_day_events_on_start_date_only'])) {
+ $value = showpass_calendar_boolean($atts['highlight_multi_day_events_on_start_date_only']);
+ if ($value !== null) {
+ $attributes['data-highlight-multi-day-events-on-start-date-only'] = $value ? 'true' : 'false';
+ }
+ }
+
+ $html = '';
+ foreach ($attributes as $name => $value) {
+ $html .= ' ' . $name . '="' . esc_attr($value) . '"';
+ }
+
+ return $html;
+}
+
//[showpass_calendar_widget]
function wpshp_calendar_widget($atts, $content = null) {
@@ -1098,7 +1225,7 @@ function wpshp_calendar_widget($atts, $content = null) {
$lang_attr = ' data-lang="'.esc_attr($atts['lang']).'"';
}
- $button = ''.$label.'';
+ $button = ''.$label.'';
return $button;
} else {
return 'Please add your Showpass Organizer ID to your Wordpress Dashboard.';
@@ -1127,7 +1254,7 @@ function wpshp_embed_calendar($atts, $content = null) {
}
if ($organization_id) {
- return '';
+ return '';
} else {
return 'Please add your Showpass Organizer ID to your Wordpress Dashboard.';
}
@@ -1149,7 +1276,8 @@ function showpass_scripts(){
wp_enqueue_script('moment-showpass');
wp_enqueue_script('moment-timezone-showpass');
wp_enqueue_script('js-cookie', plugins_url( '/js/vendor/js.cookie.js', __FILE__ ), array(), '2.2.0', true);
- wp_enqueue_script('showpass-custom', plugins_url( '/js/showpass-custom.js', __FILE__ ), array('jquery'), SHOWPASS_PLUGIN_VERSION, true);
+ wp_enqueue_script('showpass-calendar-params', plugins_url( '/js/showpass-calendar-params.js', __FILE__ ), array(), SHOWPASS_PLUGIN_VERSION, true);
+ wp_enqueue_script('showpass-custom', plugins_url( '/js/showpass-custom.js', __FILE__ ), array('jquery', 'showpass-calendar-params'), SHOWPASS_PLUGIN_VERSION, true);
}
}
@@ -1255,7 +1383,7 @@ function showpass_get_membership_data( $atts ) {
if ($template == "data") {
return $data;
- } else {
+ } else {
ob_start();
include($filepath);
$content = ob_get_clean();
diff --git a/plugin/showpass-wordpress-plugin.php b/plugin/showpass-wordpress-plugin.php
index 4332074..f0d2c4a 100644
--- a/plugin/showpass-wordpress-plugin.php
+++ b/plugin/showpass-wordpress-plugin.php
@@ -5,11 +5,11 @@
Plugin URI: https://github.com/showpass/showpass-wordpress-plugin
Description: List events, display event details and products. Use the Showpass purchase widget for on site ticket & product purchases all with easy to use shortcodes. See our git repo here for full documentation. https://github.com/showpass/showpass-wordpress-plugin
Author: Showpass / Up In Code Inc.
- Version: 4.0.8
+ Version: 4.0.9
Author URI: https://www.showpass.com
*/
-define('SHOWPASS_PLUGIN_VERSION', '4.0.8');
+define('SHOWPASS_PLUGIN_VERSION', '4.0.9');
if (! defined('ABSPATH')) {
exit;
diff --git a/showpass.zip b/showpass.zip
index 3c3ad31..599af99 100644
Binary files a/showpass.zip and b/showpass.zip differ
diff --git a/tests/CalendarShortcodeTest.php b/tests/CalendarShortcodeTest.php
new file mode 100644
index 0000000..c80a5c5
--- /dev/null
+++ b/tests/CalendarShortcodeTest.php
@@ -0,0 +1,101 @@
+ '42');
+$_SERVER['REQUEST_URI'] = '/calendar';
+require_once __DIR__ . '/../plugin/showpass-wordpress-plugin-shortcode.php';
+
+class CalendarShortcodeTest extends PHPUnit\Framework\TestCase
+{
+ public function testSpecialEventsOpenStateAndAllSelection()
+ {
+ foreach (array('wpshp_calendar_widget', 'wpshp_embed_calendar') as $shortcode) {
+ $html = $shortcode(array('calendar_open_state' => ' special-events ', 'calendar_special_event' => 'all'));
+ $this->assertContains('data-calendar-open-state="special-events"', $html);
+ $this->assertContains('data-calendar-special-event="all"', $html);
+ $this->assertContains('data-calendar-open-state="calendar"', $shortcode(array('calendar_open_state' => 'calendar')));
+ foreach (array('invalid', '', array('special-events')) as $invalid) {
+ $this->assertNotContains('data-calendar-open-state', $shortcode(array('calendar_open_state' => $invalid)));
+ }
+ }
+ }
+
+ public function testCalendarShortcodesExposeAllSdkOptions()
+ {
+ $attributes = array(
+ 'calendar_date' => '2026-09-14',
+ 'calendar_timeslot' => 'evening',
+ 'calendar_special_event' => 'opening, closing',
+ 'display_price_patron_type_id' => '17',
+ 'hide_price' => 'true',
+ 'highlight_multi_day_events_on_start_date_only' => 'true',
+ );
+
+ $modal = wpshp_calendar_widget($attributes);
+ $embedded = wpshp_embed_calendar($attributes);
+
+ foreach (array($modal, $embedded) as $html) {
+ $this->assertContains('data-calendar-date="2026-09-14"', $html);
+ $this->assertContains('data-calendar-timeslot="evening"', $html);
+ $this->assertContains('data-calendar-special-event="opening,closing"', $html);
+ $this->assertContains('data-display-price-patron-type-id="17"', $html);
+ $this->assertContains('data-hide-price="true"', $html);
+ $this->assertContains('data-highlight-multi-day-events-on-start-date-only="true"', $html);
+ }
+ }
+
+ public function testCalendarShortcodesPreserveExistingMarkupWhenOptionsAreOmitted()
+ {
+ $this->assertSame(
+ 'Get Tickets',
+ wpshp_calendar_widget(array())
+ );
+ $this->assertSame(
+ '',
+ wpshp_embed_calendar(array())
+ );
+ }
+
+ public function testCalendarShortcodesOmitMalformedTypedOptions()
+ {
+ $html = wpshp_calendar_widget(array(
+ 'calendar_date' => '',
+ 'calendar_timeslot' => array('invalid'),
+ 'calendar_special_event' => ', ,',
+ 'display_price_patron_type_id' => '0',
+ 'hide_price' => 'sometimes',
+ 'highlight_multi_day_events_on_start_date_only' => 'sometimes',
+ ));
+
+ $this->assertNotContains('data-calendar-date', $html);
+ $this->assertNotContains('data-calendar-timeslot', $html);
+ $this->assertNotContains('data-calendar-special-event', $html);
+ $this->assertNotContains('data-display-price-patron-type-id', $html);
+ $this->assertNotContains('data-hide-price', $html);
+ $this->assertNotContains('data-highlight-multi-day-events-on-start-date-only', $html);
+ }
+
+ public function testCalendarShortcodesPreserveExplicitFalseAndEscapeValues()
+ {
+ $html = wpshp_embed_calendar(array(
+ 'hide_price' => 'false',
+ 'calendar_special_event' => 'one&two',
+ ));
+
+ $this->assertContains('data-hide-price="false"', $html);
+ $this->assertContains('data-calendar-special-event="one&two"', $html);
+ }
+}
diff --git a/tests/calendar-params.test.js b/tests/calendar-params.test.js
new file mode 100644
index 0000000..0b5134b
--- /dev/null
+++ b/tests/calendar-params.test.js
@@ -0,0 +1,91 @@
+const assert = require("assert");
+const fs = require("fs");
+const vm = require("vm");
+
+const source = fs.readFileSync(
+ "plugin/js/showpass-calendar-params.js",
+ "utf8"
+);
+const sandbox = { window: {} };
+vm.runInNewContext(source, sandbox);
+
+function elementWith(attributes) {
+ return {
+ getAttribute: function (name) {
+ return Object.prototype.hasOwnProperty.call(attributes, name)
+ ? attributes[name]
+ : null;
+ },
+ };
+}
+
+function normalizedParams(attributes) {
+ return JSON.parse(
+ JSON.stringify(
+ sandbox.window.ShowpassCalendarParams.fromElement(
+ elementWith(attributes)
+ )
+ )
+ );
+}
+
+assert.deepStrictEqual(
+ normalizedParams({
+ "data-calendar-date": "2026-09-14",
+ "data-calendar-timeslot": "evening",
+ "data-calendar-special-event": "opening, closing",
+ "data-display-price-patron-type-id": "17",
+ "data-hide-price": "true",
+ "data-highlight-multi-day-events-on-start-date-only": "true",
+ }),
+ {
+ calendarDate: "2026-09-14",
+ calendarTimeslot: "evening",
+ calendarSpecialEvent: ["opening", "closing"],
+ displayPricePatronTypeId: 17,
+ hidePrice: true,
+ highlightMultiDayEventsOnStartDateOnly: true,
+ }
+);
+
+assert.deepStrictEqual(
+ normalizedParams({
+ "data-calendar-special-event": "opening",
+ "data-hide-price": "false",
+ }),
+ {
+ calendarSpecialEvent: "opening",
+ hidePrice: false,
+ }
+);
+
+assert.deepStrictEqual(
+ normalizedParams({
+ "data-calendar-special-event": ", ,",
+ "data-display-price-patron-type-id": "0",
+ "data-hide-price": "sometimes",
+ "data-highlight-multi-day-events-on-start-date-only": "sometimes",
+ }),
+ {}
+);
+
+assert.deepStrictEqual(normalizedParams({
+ "data-calendar-open-state": " special-events ",
+ "data-calendar-special-event": "all",
+}), {calendarOpenState: "special-events", calendarSpecialEvent: "all"});
+assert.deepStrictEqual(normalizedParams({"data-calendar-open-state": "calendar"}), {calendarOpenState: "calendar"});
+assert.deepStrictEqual(normalizedParams({"data-calendar-open-state": "invalid"}), {});
+
+const integrationSource = fs.readFileSync("plugin/js/showpass-custom.js", "utf8");
+assert.ok(
+ /ShowpassCalendarParams\.fromElement\(\s*this\s*\)/.test(integrationSource),
+ "modal calendar must apply the shared SDK mapper"
+);
+assert.ok(
+ /ShowpassCalendarParams\.fromElement\(\s*embeddedCalendarWidget\s*\)/.test(
+ integrationSource
+ ),
+ "embedded calendar must apply the shared SDK mapper"
+);
+
+console.log("Calendar SDK parameter tests passed.");
diff --git a/tests/card-image-widgets.test.js b/tests/card-image-widgets.test.js
new file mode 100644
index 0000000..e85ea2a
--- /dev/null
+++ b/tests/card-image-widgets.test.js
@@ -0,0 +1,49 @@
+const assert = require("assert");
+const fs = require("fs");
+
+function readTemplate(name) {
+ return fs.readFileSync("plugin/inc/" + name, "utf8");
+}
+
+const grid = readTemplate("default-grid.php");
+assert.match(
+ grid,
+ /class="showpass-image ratio banner<\?php if \(\$image_opens_widget\) echo ' open-ticket-widget'; \?>"/,
+ "event grid images must open the event widget when eligible"
+);
+assert.match(grid, /data-show-description="<\?= \$show_widget_description \?>"/);
+
+const list = readTemplate("default-list.php");
+assert.strictEqual(
+ (list.match(/\$image_opens_widget\) echo ' open-ticket-widget'/g) || []).length,
+ 2,
+ "both desktop and mobile event list images must open the event widget"
+);
+assert.strictEqual(
+ (list.match(/data-show-description="<\?= \$show_widget_description \?>"/g) || [])
+ .length,
+ 2,
+ "both event list images must pass widget description settings"
+);
+
+const membershipGrid = readTemplate("default-membership-grid.php");
+assert.match(
+ membershipGrid,
+ /class="showpass-image ratio banner open-membership-widget"/,
+ "membership grid images must open the membership widget"
+);
+assert.doesNotMatch(
+ membershipGrid,
+ /\$membership_href/,
+ "membership images must not use the undefined membership_href variable"
+);
+
+for (const productTemplate of ["default-product-grid.php", "default-product-list.php"]) {
+ assert.match(
+ readTemplate(productTemplate),
+ /class="showpass-image open-product-widget/,
+ productTemplate + " images must continue to open the product widget"
+ );
+}
+
+console.log("Card image widget template tests passed.");