Cvent for MODX 3

Public beta: the documented event-reading workflow is usable, while additional
filters, configurable price policies, retry handling and Manager tools are
planned for later releases.

Full documentation, examples, placeholder reference and troubleshooting:
https://github.com/ant-tar/cvent

CventUpcomingEvents requires a non-empty titleContains or eventIds selector.
Missing/whitespace-only selectors return empty output before any API call and
write a warning to the MODX log. Status filters alone are not course selectors.
No matches return empty output without a wrapper. toPlaceholder is cleared first.

Venue placeholders (first venue when an event has multiple venues):
location (city, regionCode, falling back to region), venueName, city, region,
regionCode, country, countryCode, address1, address2, postalCode.
Missing venue fields are empty. Escape text in HTML chunks with :htmlent.
format retains the API value; formatLabel displays Hybrid as In Person / Virtual.

Date placeholders (both event snippets):
- dateRange: English interval, e.g. October 2-4, 2026; uses the event timezone
  or the snippet timezone override. Cross-month/year intervals include both months/years.
- startTimestamp / endTimestamp: Unix seconds; empty for missing/invalid dates.
  Timestamps are absolute; MODX date modifiers use MODX/PHP timezone settings.
- start / end and startIso / endIso retain the original API date strings.
- startDate / endDate retain the existing dateFormat behavior.

Both event snippets expose priceMin, priceMax, currency, priceFormatted and price
(alias of priceFormatted). Prices use standard amounts of active, displayed
AdmissionItem fees. Early-bird pricing, discounts, refunds and QuantityItems are
excluded. Equal prices display once. Missing fees, mixed currencies or pricing
request failures produce empty price fields. Fee responses use the internal cache.

Retrieves upcoming Cvent events and renders them with MODX chunks.

The snippet does not require MODX output caching. OAuth tokens and Cvent API
responses are cached internally by the component. Use an uncached MODX call
([[!CventUpcomingEvents]]) when output must follow the API cache lifetime.

Single event by Event Code:
[[!CventEvent?
    &eventCode=`YOUR_EVENT_CODE`
    &tpl=`CventEventCard`
]]

Diagnostic Fee Items output by Event Code:
[[!CventEventFees? &eventCode=`YOUR_EVENT_CODE`]]

Required Cvent Machine-to-Machine scopes:
- event/events:read
- event/fee-items:read

Example:
[[!CventUpcomingEvents?
    &titleContains=`Course title`
    &futureOnly=`1`
    &limit=`1`
    &tpl=`CventEventCard`
]]

Parameters:
- eventIds: comma-separated Cvent event IDs (optional)
- titleContains: case-insensitive substring to match in the event title (optional)
- futureOnly: exclude events whose start time is in the past (default 1)
- status: comma-separated status values, e.g. Active or Completed (optional)
- eventStatus: comma-separated values, e.g. Upcoming or Completed (optional)
- limit: maximum number of matching events (default 1)
- tpl: output chunk (default CventEventCard)
- tplWrapper: list wrapper chunk (default CventEventList; empty disables it)
- sortBy: start, end, title, created, lastModified, status, or eventStatus
- sortDir: ASC or DESC (default ASC)
- dateFormat: PHP date format (default M j, Y g:i A T)
- timezone: output timezone; empty uses the event timezone
- cacheTime: event catalog cache lifetime; 0 uses cvent_cache_ttl
- toPlaceholder: optional placeholder that receives the complete output

Normalized placeholders include:
[[+startDate]], [[+endDate]], [[+startIso]], [[+endIso]],
[[+formatLabel]], [[+registrationUrl]], [[+summaryUrl]], [[+invitationUrl]],
[[+agendaUrl]], [[+meetingRoom]], [[+roomBlockRate]], [[+roomBlockRateExpires]],
and [[+roomBlockLink]]. Every Cvent custom field is also exposed as
[[+custom_FIELD_NAME]], normalized to lowercase underscores.

The list wrapper receives [[+output]] and [[+total]].

Requirements: MODX 3, PHP 7.4+, PHP cURL and JSON extensions, outbound HTTPS
access to Cvent, and a Cvent Machine-to-Machine application with the scopes above.
Customize copies of bundled chunks; upgrades replace the supplied chunks.
Do not expose the CventEventFees diagnostic output on public pages.

Translations: copy lexicon/en to lexicon/YOUR_LANGUAGE and translate values in
default.inc.php (including all system setting descriptions), properties.inc.php,
and setup.inc.php. Rebuild the package to include installer translations.
dateRange uses English month names; timestamps allow custom localized formatting.
