Developers English WordPress Plugin

Add to Calendar for Listeo: Developer Guide

Technical guide for safe overrides, rendering hooks, ICS URLs, shortcodes, filters, event meta, and license-safe customization.

Add to Calendar for Listeo Version 1.0 14 min read Updated Jun 30, 2026
Security boundary

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_Core is missing.
  • Listings stored as the listing post type.
  • Event data stored in Listeo listing meta.

Important files

File Responsibility
listeo-add-to-calendar.phpBootstrap, constants, dependency check, rewrite rules, clean ICS downloads, shortcodes, template helper functions, update checker.
includes/class-calendar-generator.phpReads listing event data, builds Google/Outlook/Office 365/Yahoo URLs, generates ICS content, formats dates.
includes/class-frontend.phpFrontend assets, Listeo hook placement, visibility checks, button/dropdown rendering.
includes/class-admin-page.phpAdmin menu, settings registration, settings UI, documentation screen, license screen.
includes/class-listeo-atc-license.phpLicense state and remote validation. Protected infrastructure, not a customization surface.
assets/js/add-to-calendar.jsDropdown behavior, keyboard handling, dropdown portal positioning, calendar click event dispatch.
assets/css/add-to-calendar.cssFrontend 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, or shortcode.
  • listeo_atc_show_icon: button icon flag.
  • listeo_atc_button_style: primary, secondary, or minimal.
  • 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, default event.

Event data model

Listeo_Calendar_Generator reads event data from listing post meta and WordPress post data.

Source Purpose
_listing_typeDetermines listing type. Default visible type is event.
_event_dateRequired start date/time.
_event_date_endOptional end date/time. Defaults to one hour after start if missing.
_listing_timezoneOptional timezone. Falls back to WordPress timezone.
post_titleCalendar event title.
Excerpt or contentCalendar description, stripped and trimmed.
_friendly_address or _addressCalendar location.
_geolocation_lat and _geolocation_longOptional ICS GEO property.
PermalinkMore info URL inside calendar details.

Rendering paths

Automatic insertion

Listeo_ATC_Frontend::setup_auto_insert() attaches to Listeo hooks based on listeo_atc_button_position.

Shortcode rendering

[listeo_add_to_calendar] calls Listeo_ATC_Frontend::render_button() with optional button arguments.

Template helpers

listeo_add_to_calendar_button() echoes markup. get_listeo_add_to_calendar_button() returns markup.

Archive shortcode

[listeo_atc_archive] queries published event listings with _event_date.

Listeo hook mapping

Position Hook / behavior
after_titlelisteo/single-listing/tags at priority 20.
sidebarlisteo/single-listing/sidebar-start at priority 20, wrapped in a boxed widget.
before_contentlisteo/single-listing/before-content at priority 10 with the_content fallback.
after_contentlisteo/single-listing/after-content at priority 10 with the_content fallback.
shortcodeNo 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_pathsAdjust ListingPilot hub render file discovery.
listingpilot_dashboard_listAdd or modify the addon card in the central ListingPilot dashboard.
listeo_atc_sidebar_icon_classChange the sidebar widget icon class.
listeo_atc_sidebar_titleChange the sidebar widget heading.
listeo_atc_enqueue_assetsOverride frontend CSS/JS loading logic.
listeo_atc_show_buttonFinal visibility decision for a listing button.
listeo_atc_button_argsModify 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

  1. Confirm Listeo_Core exists and the plugin initialized.
  2. Confirm the listing post type is listing.
  3. Check _event_date and verify the date format can be parsed.
  4. Check _listing_type and the listeo_atc_listing_types option.
  5. Confirm at least one provider option is enabled.
  6. Confirm frontend assets are enqueued on the current page.
  7. Test the clean ICS URL and check for 403 token errors or 404 event data errors.
  8. 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.