Add to Calendar for Listeo: Developer Guide
Technical guide for safe overrides, rendering hooks, ICS URLs, shortcodes, filters, event meta, and license-safe customization.
License activation, update authorization, package downloads, entitlement checks, stored license status, and remote validation responses are not extension points. Do not override license AJAX actions or update callbacks to unlock paid behavior.
Scope
This guide is for developers extending Add to Calendar for Listeo from a child theme, site plugin, or mu-plugin. It covers real rendering paths, data sources, shortcodes, filters, ICS downloads, and safe override points.
Runtime requirements
- WordPress 5.8 or newer.
- PHP 7.4 or newer.
- Listeo Core active. The plugin does not initialize frontend/admin classes if
Listeo_Coreis missing. - Listings stored as the
listingpost type. - Event data stored in Listeo listing meta.
Important files
| File | Responsibility |
|---|---|
listeo-add-to-calendar.php | Bootstrap, constants, dependency check, rewrite rules, clean ICS downloads, shortcodes, template helper functions, update checker. |
includes/class-calendar-generator.php | Reads listing event data, builds Google/Outlook/Office 365/Yahoo URLs, generates ICS content, formats dates. |
includes/class-frontend.php | Frontend assets, Listeo hook placement, visibility checks, button/dropdown rendering. |
includes/class-admin-page.php | Admin menu, settings registration, settings UI, documentation screen, license screen. |
includes/class-listeo-atc-license.php | License state and remote validation. Protected infrastructure, not a customization surface. |
assets/js/add-to-calendar.js | Dropdown behavior, keyboard handling, dropdown portal positioning, calendar click event dispatch. |
assets/css/add-to-calendar.css | Frontend button, dropdown, provider icons, sidebar and responsive styling. |
Constants and options
LISTEO_ATC_VERSION,LISTEO_ATC_PATH,LISTEO_ATC_URL,LISTEO_ATC_BASENAME.listeo_atc_enabled: global frontend enable flag.listeo_atc_button_text: default button label.listeo_atc_button_position:after_title,sidebar,before_content,after_content, orshortcode.listeo_atc_show_icon: button icon flag.listeo_atc_button_style:primary,secondary, orminimal.listeo_atc_show_google,listeo_atc_show_apple,listeo_atc_show_outlook,listeo_atc_show_office365,listeo_atc_show_yahoo,listeo_atc_show_ics: provider visibility flags.listeo_atc_listing_types: allowed Listeo listing types, defaultevent.
Event data model
Listeo_Calendar_Generator reads event data from listing post meta and WordPress post data.
| Source | Purpose |
|---|---|
_listing_type | Determines listing type. Default visible type is event. |
_event_date | Required start date/time. |
_event_date_end | Optional end date/time. Defaults to one hour after start if missing. |
_listing_timezone | Optional timezone. Falls back to WordPress timezone. |
post_title | Calendar event title. |
| Excerpt or content | Calendar description, stripped and trimmed. |
_friendly_address or _address | Calendar location. |
_geolocation_lat and _geolocation_long | Optional ICS GEO property. |
| Permalink | More info URL inside calendar details. |
Rendering paths
Listeo_ATC_Frontend::setup_auto_insert() attaches to Listeo hooks based on listeo_atc_button_position.
[listeo_add_to_calendar] calls Listeo_ATC_Frontend::render_button() with optional button arguments.
listeo_add_to_calendar_button() echoes markup. get_listeo_add_to_calendar_button() returns markup.
[listeo_atc_archive] queries published event listings with _event_date.
Listeo hook mapping
| Position | Hook / behavior |
|---|---|
after_title | listeo/single-listing/tags at priority 20. |
sidebar | listeo/single-listing/sidebar-start at priority 20, wrapped in a boxed widget. |
before_content | listeo/single-listing/before-content at priority 10 with the_content fallback. |
after_content | listeo/single-listing/after-content at priority 10 with the_content fallback. |
shortcode | No automatic hook output. |
Shortcodes and helpers
[listeo_add_to_calendar listing_id="123" button_text="Save Event" show_icon="true"]
[listeo_atc_archive limit="20" listing_type="event"]
<?php
listeo_add_to_calendar_button(123, [
'button_text' => 'Save Event',
'show_icon' => true,
]);
$html = get_listeo_add_to_calendar_button(123);
?>
ICS downloads
The plugin registers the rewrite rule ^calendar/([^/]+)\.ics$ and maps it to the query var listeo_calendar_download. Public download URLs look like this:
/calendar/event-slug.ics?t=generated-token
The token is generated with HMAC from the listing ID and WordPress AUTH_KEY. Invalid tokens return 403. Missing listings or missing event data return 404.
The legacy AJAX action listeo_download_ics exists for backward compatibility and redirects to the clean URL after nonce validation.
Supported filters
| Filter | Use |
|---|---|
listingpilot_hub_render_paths | Adjust ListingPilot hub render file discovery. |
listingpilot_dashboard_list | Add or modify the addon card in the central ListingPilot dashboard. |
listeo_atc_sidebar_icon_class | Change the sidebar widget icon class. |
listeo_atc_sidebar_title | Change the sidebar widget heading. |
listeo_atc_enqueue_assets | Override frontend CSS/JS loading logic. |
listeo_atc_show_button | Final visibility decision for a listing button. |
listeo_atc_button_args | Modify button arguments before rendering. |
Safe override examples
Load assets on a custom event landing page:
add_filter('listeo_atc_enqueue_assets', function (bool $enqueue): bool {
return $enqueue || is_page('events');
});
Hide the button for one listing:
add_filter('listeo_atc_show_button', function (bool $show, int $listing_id): bool {
if ($listing_id === 123) {
return false;
}
return $show;
}, 10, 2);
Change the sidebar widget title and icon:
add_filter('listeo_atc_sidebar_title', function (string $title, int $listing_id): string {
return 'Save This Event';
}, 10, 2);
add_filter('listeo_atc_sidebar_icon_class', function (string $class, int $listing_id): string {
return 'fa-regular fa-calendar-check';
}, 10, 2);
Change button copy from a site plugin:
add_filter('listeo_atc_button_args', function (array $args, int $listing_id): array {
$args['button_text'] = 'Save to Calendar';
return $args;
}, 10, 2);
Frontend JavaScript
The dropdown script listens for clicks on .listeo-add-to-calendar-btn, moves the dropdown to a portal when needed, handles keyboard navigation, closes on outside click, and dispatches listeo:calendar_add after a provider link is selected.
document.addEventListener('listeo:calendar_add', function (event) {
console.log(event.detail);
});
Debugging checklist
- Confirm
Listeo_Coreexists and the plugin initialized. - Confirm the listing post type is
listing. - Check
_event_dateand verify the date format can be parsed. - Check
_listing_typeand thelisteo_atc_listing_typesoption. - Confirm at least one provider option is enabled.
- Confirm frontend assets are enqueued on the current page.
- Test the clean ICS URL and check for 403 token errors or 404 event data errors.
- Temporarily switch Button Position to Shortcode only and render a known listing by ID.
Do not customize here
- License activation and deactivation AJAX handlers.
- License key/status options or remote validation responses.
- Plugin update checker callbacks.
- HMAC token validation for ICS downloads.
- ICS output escaping and CRLF injection protections.
- Any code that grants paid behavior to an unlicensed site.