Author Archive

Listeo Update 2.2.4 Report

Listeo 2.2.4 is out, together with a big update to Listeo Monetization Plus. The headline is Banner Ads: a new way to earn money from your directory by selling ad space directly to local businesses. On the Listeo side, you get a calendar view for bookings, a custom region URL base, lighter gallery uploads and a round of map and security fixes.

  • Banner Ads: sell ad space on your directory, with a self-serve booking page and WooCommerce payments.
  • Bookings calendar: see every booking by month, week or agenda in wp-admin.
  • Region base: replace /region/ in your URLs with your own word.
  • Lighter uploads: photos are scaled down in the browser before they are uploaded.
  • Fixes: maps, date search, listing descriptions and security hardening.

Banner Ads: sell ad space on your directory

Your directory already has the audience that local businesses want to reach. Banner Ads, a new module in Listeo Monetization Plus, lets them buy that visibility without emailing you or waiting for an invoice.

How it works

  1. You create zones
    A zone is a place on your site with a size and a price per day. Put one between search results, in the search sidebar, on single listing pages, above the header, above the footer, or anywhere with a shortcode, widget or Elementor widget.
  2. Advertisers book them
    The Advertise page walks them through three steps: pick a spot, choose dates on a live availability calendar, and upload a banner that is cropped to the right size in the browser. They see the total price, including long-campaign discounts, and pay through your regular WooCommerce checkout.
  3. You approve
    Paid banners wait for your review (or switch on automatic approval). Approve them, or reject with a reason that is emailed to the advertiser so they can fix and resend.

What else is included

A dashboard for you
Impressions, clicks, CTR, sales, zone occupancy for the next 30 days and your top banners.
My Ads for advertisers
Advertisers track impressions, clicks and CTR, edit their banner and book the same spot again from their Listeo dashboard.
Category and region targeting
Sell a zone separately per category or region, so a restaurant can book the banner on restaurant searches only (set the zone capacity to 1 to make it exclusive).
No empty spots
When nothing is booked, a zone can show your own house banners or a code snippet such as AdSense.
Works with page caching
Banners rotate on cached pages, and WP Rocket, LiteSpeed Cache, W3 Total Cache and WP Super Cache are cleared automatically when banners change.
Honest tracking
An impression counts only when at least half of the banner is visible for one second. Bots are ignored, and visitor IP addresses are never saved with your statistics.
Any WooCommerce gateway
Advertisers pay through your checkout with any gateway, bank transfer included. Dates are held while they pay.
Nine emails
Every step is covered, from payment received to “your banner ends soon”, and every email is editable.

Banner Ads is off by default. Turn it on in Listeo Core > Banner Ads > Settings, create your first zone, and add the Advertise page to your menu or footer so advertisers can find it. Step-by-step setup: Banner Ads guide.

Subscriptions no longer just expire

Also new in Monetization Plus: when a listing subscription lapses (cancelled, paused or unpaid), live listings can move to a fallback package, for example a Free plan, instead of disappearing from your directory. When the subscriber renews, the listings move back to the paid plan.

Set the fallback package on the listing package product in Listeo Core. This applies to the “Listings stay live while the subscription is active” mode. Listings beyond the fallback package’s limit expire as before.

Listeo Monetization Plus
Banner Ads, subscriptions and more ways to earn from your directory.
Get Monetization Plus

What’s new in Listeo 2.2.4

Calendar view for bookings
Listings > Bookings has a new Calendar tab with month, week and agenda views, the same filters as the list, and shaded owner-blocked days when one listing is selected.
Your own region URL base
Replace /region/ with your own word in Settings > Permalinks > Region base. Permalink changes now take effect after a single save.
Lighter, safer gallery uploads
Photos are scaled to 2560 px in the browser before upload, fewer image sizes are created, and failed uploads are clearly marked.
Map fixes
Fresh OpenStreetMap tiles, a reliable all-listings map with location radius, individual markers with clustering off, and a better “Find my location”.

Calendar view for bookings

The Calendar tab loads up to 500 bookings at a time, hides cancelled and expired bookings unless you pick that status in the filter, and clicking a booking opens its details. The booking list filters also work again: they no longer end on “Sorry, you are not allowed to access this page”.

Your own region URL base

Not every directory is in English. Leave the new field empty to keep your current /region/ URLs. A base that collides with another Listeo base is refused with a notice.

Lighter, safer gallery uploads

Smaller uploads mean fewer timeouts on shared hosting, and scaled photos are sent without camera metadata such as GPS position. Adjust the size in Listeo Core > Submit Listing, or set it to 0 to upload originals. The form waits until every image has finished uploading.

Map fixes

  • Tiles: OpenStreetMap tiles load from the current tile server.
  • Location radius: the all-listings map keeps working after a visitor shares their location with a search radius.
  • Clustering off: the all-listings map shows individual markers (very dense areas still group until you zoom in).
  • Find my location: with OpenStreetMap it keeps your zoom level and no longer moves another listing’s marker, and with Google Maps the results now refresh.

Other improvements

  • Promotions: “Listeo Ads” is now called Promotions everywhere in the interface. Only the wording changed, your settings and data stay the same.
  • Admin menu: Listeo Core settings are grouped into Settings, Tools, Add-ons and Licenses.
  • Date search: date range search reads day-first dates with month names correctly (for example “25 декабря 2026”).
  • Descriptions: listing descriptions keep their paragraph breaks after editing in both the block editor and the dashboard.
  • Bulk updates: updating plugins from Appearance > Install Plugins no longer stops with an error when one plugin needs a newer PHP or WordPress version.

Security

This release includes security hardening in Listeo Core and Listeo Forms & Fields Editor, covering the bookings admin screen, gallery uploads, permalink settings and the form builder. We recommend updating all sites.

How to update

  1. Download the latest package
    Get the newest Listeo files from purethemes.net/license.
  2. Update the theme and plugins together
    Update the Listeo theme, Listeo Core, Forms & Fields Editor and Listeo Elementor, since some fixes need both. Follow How to update the theme and plugins.
  3. Update Monetization Plus and clear your cache
    If you use Listeo Monetization Plus, update it as well to get Banner Ads. Then clear your site cache.

Full list of changes: Listeo changelog.

FAQ

  • Do I need Listeo Monetization Plus for Banner Ads?

  • Which payment methods can advertisers use?

  • Will Banner Ads change my site right after the update?

  • Does the Promotions rename change my existing promoted listings?

  • I use a page cache. Will banners still rotate?

Banner Ads

Banner Ads lets you sell banner space on your directory. You create zones (places on the site with a size and a price per day), advertisers book dates and pay through WooCommerce, and you approve their banners before they go live. This article walks through enabling the module, creating zones, selling them, moderating banners and testing the full flow.

What Banner Ads Does

Banner Ads is bundled with the Listeo Monetization Plus plugin. It needs WooCommerce, and Listeo theme and Listeo Core 2.2.3 or newer.

You can use it in three ways, and mix them freely:

  • Self-serve sales. Advertisers pick a spot and dates on the Advertise page, upload their banner, pay through WooCommerce and follow their results on My Ads.
  • Banners you add yourself. For deals made outside the site, add the banner in wp-admin and set its dates.
  • House banners and ad code. When nothing is booked, a zone can show your own promo banners or a code snippet (for example AdSense) instead of staying empty.

Image banners count impressions and clicks, and you see the results per zone and per banner on the Banner Ads dashboard.


Where to Find It

Go to WP Admin → Listeo Core → Banner Ads. You’ll find five tabs:

  • Dashboard: impressions, clicks, CTR and sales for the last 7, 30 or 90 days, how full each zone is over the next 30 days, and your top banners.
  • Zones: the places on your site where banners show.
  • Banners: every banner with its zone, dates, status and results. Banners bought on the Advertise page wait here for your review.
  • Emails: the messages sent to advertisers and to you.
  • Settings: the on/off switch, sponsored label, link attributes, pages, checkout and upload rules.

A red number next to the menu item shows how many banners are waiting for review.


Step 1: Turn It On

Banner Ads is off by default.

  1. Open Banner Ads → Settings.
  2. Under Enable Banner Ads, switch on Show banners.
  3. Check the Label. It defaults to Sponsored and is shown with every banner, house banners and ad code included. Many countries require paid content to be marked, so we recommend keeping it.
  4. Save.

When the plugin is activated, Banner Ads also creates two pages for you:

Page Shortcode What it’s for
Advertise With Us [lpba_advertise] Where advertisers choose a spot and dates, upload their banner and go to checkout.
My Ads [lpba_my_ads] The advertiser’s list of banners with results, payment and edit options. It uses the dashboard page template.

You can assign different pages in Settings → Pages. Each page must contain its shortcode.

Add the Advertise page to your menu or footer so advertisers can find it. The My Ads item appears in the user dashboard menu automatically once a user has a banner.


Step 2: Create a Zone


A zone is one place on the site with one banner size. Go to Banner Ads → Zones and click Add zone.

Place

  • Zone name: advertisers see it on the Advertise page, so make it descriptive, for example “Search results top”.
  • Location: where the zone shows. Each option has a small sketch of the page.
Location Where it shows
Search results Above the results, below the results, in the sidebar (top), or between listings (every N). The in-feed option shows the banner as one more card in the results grid, after every N listings, counted across pages and AJAX filtering. Sponsored listing cards do not count.
Single listing Sidebar (top or bottom), after the description, after the Overview section (below Features), or after the location (before reviews).
Whole site Top of the page above the header, or above the footer.
Manual Nowhere automatically. You place it yourself with the shortcode, the widget or the Elementor widget (see Step 3).

Size

Pick a Format: 728 × 90 Leaderboard, 970 × 250 Billboard, 300 × 250 Medium Rectangle, 300 × 600 Half Page, 320 × 50 Mobile Banner, 320 × 100 Large Mobile Banner, or Custom size. Advertisers upload images in these proportions, and the upload tool crops them to fit.

Display

Setting What it does
Banners at the same time 1 makes the zone exclusive: one banner per day. With more, banners booked for the same days rotate on each page view.
Targeting None (everywhere the zone shows), Category or Region. With targeting, each category or region has its own calendar, so you can sell the same spot to a different advertiser per category. A targeted banner takes priority over banners shown everywhere.
When nothing is booked Show nothing, House banners of this zone, or Code (e.g. AdSense). Fallback code can only be edited by administrators.

Selling

Switch on Sell this zone to offer it on the Advertise page, then set:

  • Price per day. A zone is offered only when it is for sale and has a price above zero.
  • Earliest start (days from today), Shortest booking and Longest booking.
  • Long booking discounts (optional): up to three tiers, for example “From 30 days take off 10%”. The best matching discount applies.

Leave Sell this zone off for zones you want to fill only with banners you add yourself.

Click Create zone. The zone card shows its shortcode, how many of the next 30 days are booked, and Pause / Edit buttons.

Pausing a zone hides it and all its banners, paid ones too, and removes it from the Advertise page. Bookings stay, but the paid days keep running. A zone that has banners (including banners in the trash) cannot be deleted; pause it instead.


Step 3: Place Manual Zones

Zones with an automatic location need nothing more. For a Manual zone, use one of these:

  • Shortcode: [lpba_zone id="123"]. Copy it from the zone card.
  • Widget: Listeo Banner Zone in Appearance → Widgets.
  • Elementor: the Banner Zone widget.

To keep in-feed banners out of a particular listings list, use [listings banners="no"], or switch off Banners between listings in the Elementor Listings widget.


Step 4: Set Up Selling

Open Banner Ads → Settings and review the Selling and Image uploads sections:

Setting Default What it does
Approve paid banners automatically Off Paid banners go live without your review. This also applies when advertisers change the image or link of an approved banner. Not recommended: check images and links first.
Allow WooCommerce coupons Off Lets coupons apply to banner purchases.
Reserve the dates during checkout 30 minutes How long the chosen days are held while the advertiser pays. Once an online order is placed, the reservation is extended to twice this time.
Reserve the dates for offline payments 3 days How long an order paid by bank transfer, cheque or cash on delivery keeps its days.
Remind before the end 3 days When to send the “ends soon” email. 0 turns it off.
Advertising terms None Choose a page and advertisers must accept it before paying.
Maximum file size 300 KB Largest banner image after cropping. Animated GIFs must fit this limit as uploaded.
Allowed difference in proportions 2% How far an uploaded image may differ from the zone’s proportions. In practice this matters for animated GIFs, because other images are cropped exactly.

Under Links, banner links always get rel="sponsored". You can also add nofollow and open links in a new tab (both on by default).


How Buying Works

For Advertisers

Any logged-in user can book a banner. Guests see the spots and are asked to log in or create an account. The Advertise page has three steps:

  1. Spot: choose a zone. Each card shows the size, the shortest booking, the price per day and any long-campaign discount. If the zone uses targeting, the advertiser can also choose a category or region, or keep “Everywhere this spot shows”.
  2. Dates: pick a range on the calendar, which shows booked days, or use a ready-made length.
  3. Your Banner: upload an image, crop it to the spot in the browser, and add the link and optional alt text. JPG, PNG and WebP are cropped and compressed automatically. Animated GIFs are not cropped, so they must already have the right proportions and size.

The Your campaign sidebar shows a live preview and the total. Continue to payment holds the dates and sends the advertiser to the WooCommerce checkout.

Behind the Scenes

All banner purchases go through one hidden WooCommerce product called Banner placement, created automatically. It cannot be bought directly, and you only need to edit it to change its tax class. The price is calculated on the server from the zone, the dates and the discount.

  • Order placed: the held days become a reservation, longer for offline payments.
  • Order paid: the banner moves to Pending review (or straight to Scheduled/Active with automatic approval). Orders that contain only banners are completed automatically.
  • Cash on delivery: the banner is activated only when you mark the order Completed.
  • Order cancelled or refunded: the days are released and the banner is cancelled. Partial refunds don’t change the banner.
  • No order placed in time (or the banner was removed from the cart): the banner becomes Abandoned (not paid) and its days are released.
  • Order placed but not paid in time (for example a bank transfer that never arrives): the days are released when the reservation runs out. The banner stays Waiting for payment until you cancel the order.

Tax follows the tax settings of your WooCommerce store and the tax class of the Banner placement product (Standard by default). To change it, edit the product in Products; it is hidden from the shop but listed there.


Step 5: Review and Approve Banners


Paid banners wait in Banner Ads → Banners with the status Pending review, and you get an email.

  1. Use the Pending review filter at the top of the list.
  2. Check the image and the link (open the banner with Edit to see it in full).
  3. Click Approve in the banner’s row. In the banner editor, set Status to Approved (runs on its dates) and save instead. The banner becomes Scheduled or, if its first day has come, Active.

To reject, open the banner, set Status to Rejected and fill in Reason (sent to the advertiser). The advertiser gets an email and can change the image or link on My Ads and send it again.

Rejecting a banner does not refund the order. If you won’t run the banner, refund the order in WooCommerce, which also releases the days.

The list also has bulk actions (Approve, Pause, Resume, Move to trash) and filters by zone, type and advertiser.

Banner Statuses

Status Meaning
Waiting for payment Booked on the Advertise page, not paid yet. The days are held until the reservation time runs out.
Pending review Paid, or changed by the advertiser, and waiting for you.
Scheduled Approved, its first day hasn’t come yet.
Active Showing on the site.
Paused Stopped by you. Resume it from the list.
Expired Its last day has passed.
Rejected / Cancelled Not running. Their days are released.
Abandoned (not paid) No order was placed in time. Deleted automatically 30 days after the booking was started.


Adding Banners Yourself

Click Add banner in the Banners tab. Choose the image (or HTML / code, administrators only), link, zone and one of two types:

  • Paid banner (runs on its dates): for deals made outside the site. It books the zone’s days like a purchase. If the zone is already full on some days, the banner is still saved with a warning and rotates with the others. You can assign it to a user so it appears on their My Ads page, where they can also change its image and link.
  • House banner (fills the zone when nothing is booked): your own promo, with no dates. It shows only when the zone’s When nothing is booked option is set to house banners and no paid banner is running.

Emails go only to advertisers who bought on the Advertise page. Banners you add yourself never email the assigned user.


My Ads (Advertiser Dashboard)

Advertisers see all their banners on My Ads, with dates, status, impressions, clicks, CTR and price. From there they can:

    dzr

  • Pay now or Cancel a booking that isn’t paid yet.
  • Edit banner: replace the image, re-crop it, or change the link and alt text.
  • Book again: start a new booking for the same spot. For a running or scheduled banner, the new dates start the day after the current ones end.

After an advertiser changes an approved banner, it goes back to Pending review and stops showing until you approve the changes, while its paid days keep running. The advertiser sees this warning before saving. With automatic approval on, changes go live right away.


Emails

In Banner Ads → Emails, each message can be switched off and its subject and text changed. Leave a field empty to use the default text, which is translated (into the advertiser’s language for advertiser emails, and the site language for yours).

To the advertiser To you
Payment received, Banner approved, Banner rejected, Banner is live, Ending soon, Banner ended (with results) Banner to review, New sale (auto-approved), Paid over capacity

Available tags: {advertiser_name} {zone} {dates} {end_date} {price} {banner_url} {reason} {impressions} {clicks} {ctr} {my_ads_url} {renew_url} {review_url} {site_name} {contact_email}

Set Send the emails for you to if admin emails should go somewhere other than the site admin address.


Statistics and Caching

  • An impression counts when at least half of the banner is visible for one second. HTML / code banners and fallback code (AdSense) are not counted.
  • A click counts once per visitor and banner every 30 minutes. Bots are ignored, and no IP addresses are stored.
  • Banners work with page caching: the page carries all eligible banners and the visitor’s browser picks one, so rotation and dates stay correct on cached pages. Banner and zone changes clear the cache of WP Rocket, LiteSpeed Cache, W3 Total Cache and WP Super Cache.
  • Banner markup and images uploaded on the Advertise page avoid typical ad-related names, which helps them get past many ad blockers. Third-party ad code such as AdSense will still be blocked.

If you use Delay JavaScript execution in WP Rocket (or a similar option in another plugin), exclude the inline script lpz. Otherwise banners don’t rotate and impressions aren’t counted until the visitor interacts with the page.


Step 6: Test It

  1. Create a zone with a price, switch on Sell this zone, and make sure Show banners is on.
  2. Log in as a regular user (not an admin) and open the Advertise page. Choose the zone, dates and an image, then click Continue to payment.
  3. Pay with a test gateway (or bank transfer, then mark the order Completed).
  4. As admin, open Banner Ads → Banners, find the banner in Pending review and approve it.
  5. Visit a page where the zone shows on one of the booked days. Confirm the banner appears with its label, and that clicking it opens the advertiser’s link.
  6. As the advertiser, open My Ads and confirm the banner, its status and its results are listed.


FAQ

  • Do I need WooCommerce?

  • Can I sell banners without letting advertisers book them online?

  • Can more than one banner share a zone?

  • Can I charge different prices per category?

  • What happens when I change a zone's price?

  • Can I show AdSense when no banner is booked?

  • Are there limits for advertisers?

  • Are statistics kept when a banner is deleted?


Troubleshooting

  • The Advertise page shows the shortcode as text

  • A zone isn't offered on the Advertise page

  • A paid banner isn't showing

  • A banner says it needs new dates

  • Impressions stay at zero

  • The 'Above the footer' zone doesn't appear


For Developers

  • Templates can be overridden by copying advertise.php, my-ads.php or creative-fields.php to a listeo-banner-ads/ folder in your child theme.
  • Useful filters: lpba_render_locations (add or remove locations), lpba_price (booking price), lpba_eligible_banners (banners shown in a zone), lpba_length_presets (ready-made booking lengths), lpba_offline_payment_methods, lpba_advertiser_can_edit_creative, lpba_email_subject / lpba_email_body.
  • Useful actions: lpba_banner_status_changed, lpba_order_fulfilled, lpba_notify.
  • For a page cache that isn’t cleared automatically, add your purge function with the lpba_purge_cache filter.
  • To remove all zones, banners and statistics when the plugin is deleted, switch on Delete data on uninstall in Settings (off by default).

How to use custom SMS provider with Listeo Notifications add-on

Send SMS through a local gateway instead of Twilio by adding one filter, so every notification and OTP goes out through any provider with an HTTP API, and your code survives plugin updates.


Before you start

This part is for developers. It needs a small code snippet, so skip it if Twilio works for you.

Twilio works almost everywhere, but local and domestic SMS gateways are often far cheaper for a site that only sends to one country. Listeo Notifications & OTP Verification 2.0 adds two filters that let you plug in any gateway with an HTTP API. Twilio stays the default provider: nothing changes on your site unless you add the snippet below.

You will need:

  • Listeo Notifications & OTP Verification 2.0 or later. The filters do not exist in earlier versions.
  • An SMS gateway with an HTTP API, plus its endpoint URL and credentials.
  • Someone comfortable writing a few lines of PHP.

Note One filter covers everything the add-on sends: around 20 booking and listing notifications, the scheduled booking reminders, and the phone OTP used by registration and login. They all pass through the same send function.


Step 1: Put your code in the right place

Your snippet must live outside the add-on, or the next update will delete it.

  1. Recommended – a small plugin of your own, or a single file in wp-content/mu-plugins/. Files in mu-plugins load automatically and need no activation.
  2. Recommended – your child theme’s functions.php.
  3. Never – inside the Listeo Notifications & OTP Verification plugin folder. Editing the add-on’s own files means losing the change on every update, which is exactly the problem this filter solves.

Warning – Do not edit class-listeo-notifications.php or any other file inside the add-on. Use the filter instead. Plugin updates overwrite those files without asking.


Step 2: Add the filter

The filter is listeo_sms_pre_send. Return null and Listeo keeps using Twilio exactly as before. Return anything else and Twilio is never called.

Paste this into the file you created in Step 1, then replace the endpoint and credentials with the ones from your gateway.

<?php

add_filter( 'listeo_sms_pre_send', function( $result, $to, $body ) {

    $endpoint = 'https://gateway.example.com/api/send';
    $username = 'my-user';
    $token    = 'my-token';

    $response = wp_remote_post( $endpoint, array(
        'timeout' => 15,
        'headers' => array(
            'Authorization' => 'Bearer ' . $token,
            'Content-Type'  => 'application/json',
        ),
        'body' => wp_json_encode( array(
            'username' => $username,
            'to'       => ltrim( $to, '+' ),
            'message'  => $body,
        ) ),
    ) );

    if ( is_wp_error( $response ) ) {
        return array(
            'sent'   => false,
            'status' => 'error',
            'error'  => $response->get_error_message(),
        );
    }

    $code = wp_remote_retrieve_response_code( $response );
    $data = json_decode( wp_remote_retrieve_body( $response ), true );

    if ( 200 !== $code ) {
        return array(
            'sent'   => false,
            'status' => 'error',
            'error'  => isset( $data['message'] ) ? $data['message'] : 'HTTP ' . $code,
        );
    }

    return array(
        'sent'   => true,
        'id'     => isset( $data['message_id'] ) ? $data['message_id'] : '',
        'status' => 'sent',
        'error'  => '',
    );

}, 10, 3 );

What your callback receives

  1. $to – the destination number, already normalized by Listeo, so you do not repeat that work. International input, and any national number that your Default country code setting can complete, arrives in E.164 with a leading plus, for example +972501234567. A number written with 00 instead of a plus is treated as international too, so 0049… resolves even with no default country code set. If a visitor types a national number without a country code and the site has no default country code configured, the number is passed through with every non-digit character removed. That is the same value Twilio would have received, so if your gateway requires E.164, check for the leading plus yourself.
  2. $body – the finished message text, with all merge tags already replaced.

If your gateway expects a local format rather than E.164, strip the prefix in your callback, for example ltrim( $to, '+' ).

What your callback can return

  1. null – keep the built-in Twilio transport. Twilio runs exactly as before. This is also what happens when no callback is attached at all.
  2. true or false – the message was sent, or it failed. Enough if you do not need the delivery log to show your gateway’s own message id.
  3. WP_Error – failed. Its error message is stored with the delivery log entry.
  4. An array – array( 'sent' => bool, 'id' => string, 'status' => string, 'error' => string ). sent tells Listeo whether delivery succeeded, id and status are your gateway’s own message id and status (recorded in the delivery log the same way a Twilio message SID is), and error is the reason shown when sent is false.
  5. Listeo_Notification_Result – accepted as well, so a callback written for the WhatsApp filter below cannot misfire here. On the WhatsApp filter the result is used exactly as it is. On listeo_sms_pre_send only its sent or failed state, its message and its provider id are kept, and a skipped() result counts as not sent (logged as a deliberate skip rather than an error) because this filter has no third state to report.
  6. Any other value – treated as a failed send. Listeo never assumes that an unrecognized value means success, so a mistake in your callback appears in the delivery log instead of producing an OTP that was never delivered.

Note The sent key is checked with PHP’s empty(), so false, 0, '' and the string '0' all count as “not sent”.


Step 3: Turn Debug Mode off and send a test

Debug Mode is evaluated before the filter. While it is on, every message is simulated and logged and your gateway is never contacted, so you cannot test a custom gateway with Debug Mode enabled.

  1. Go to Listeo Core > Notifications > Logs & Debug and turn Debug Mode off.
  2. Trigger a real message, for example request a login OTP or place a test booking.
  3. Come back to Logs & Debug and check the Delivery history table.

Where to see the result

The Delivery history table lists Time, Event, Recipient, Channel and Status as columns. The provider message id and the error text your callback returned are behind View details in the Details column.

Tip Test with an OTP request rather than a booking. It is the fastest round trip, it goes through the same send function, and it tells you immediately whether your gateway accepted the number format.


Sending WhatsApp through your own gateway

WhatsApp has its own send path, so it has its own filter: listeo_notification_whatsapp_pre_send. It runs before both the Twilio and the Meta Cloud API WhatsApp providers.

It takes one argument more than the SMS filter, so register it with 10, 4:

add_filter( 'listeo_notification_whatsapp_pre_send', function( $result, $to, $body, $context ) {
    // Same return values as listeo_sms_pre_send.
    return null;
}, 10, 4 );
  1. $context – holds the merge-tag values used to build the message, and array( 'test' => true ) when the message comes from the admin test button. Use it if your gateway needs extra data about the message.
  2. $to – always valid E.164 with a leading plus here. The WhatsApp channel rejects anything else before the filter runs, so the “no default country code” case cannot reach it.

The accepted return values are the same as for listeo_sms_pre_send, and the outcome is logged the same way.


Troubleshooting


  • Messages do not seem to go anywhere

  • The delivery log shows a failure although you think the callback worked

  • Your gateway rejects the number

  • Nothing you do has any effect


Important Your callback runs on every SMS the site sends, including the login and registration OTP. If it throws or hangs, phone verification stops working. Keep the request timeout short, handle is_wp_error(), and test an OTP request before you consider the integration done.


Other developer hooks

This add-on exposes more hooks than the two above, including listeo_sms_normalize_phone for country-specific numbering rules, listeo_sms_otp_request_allowed and listeo_sms_otp_global_hourly_limit for OTP rate limiting, listeo_notification_channels and listeo_notification_channel_allowed for the channel layer, and listeo_notification_whatsapp_meta_payload for approved WhatsApp templates. They are documented in the Listeo Developer Hooks Reference.

How to Set Up and Use Listeo PWA

Turn your Listeo website into an installable app.
Visitors can add it to their phone or computer, while opened booking details and eligible QR tickets stay available offline.

The installed app uses your existing WordPress website. Browsing current listings, creating or changing bookings, payments, messages and account changes still require an internet connection.


Before you start

You need:

  • WordPress 6.0 or newer and PHP 7.3 or newer.
  • Listeo Core 2.1.8 or newer.
  • An active Listeo PWA license
  • HTTPS enabled on the whole website.
  • A square WordPress Site Icon, at least 512 × 512 pixels, in PNG, JPEG or WebP format.
  • No other PWA plugin active.

The Site Icon is required. Set it in Appearance → Customize → Site Identity or directly in Listeo → PWA Settings.


Install and configure Listeo PWA

  1. Go to Plugins → Add New → Upload Plugin.
  2. Upload listeo-pwa.zip, then install and activate it.
  3. Open Listeo → PWA License and activate your license.
  4. Open Listeo → PWA Settings.
  5. Set the Site Icon and enable Enable PWA.
  6. Adjust the app name, colors, install suggestion and offline options.
  7. Save the settings, then purge page, CDN and hosting caches.
  8. Run Installation check and test the app on a real phone.

If you use Cloudways or another host with Varnish, purge Varnish after changing PWA settings. Cached manifest or service worker responses can prevent installation.


Let visitors install the app

The automatic installation suggestion can appear on all screens, mobile only or desktop only. You can set a delay and include or exclude specific page IDs. Checkout and booking payment pages are always excluded.

You can also add a permanent install button with:

  • [listeo_pwa_install]
  • [listeo_pwa_install text="Get the app"]
  • The Listeo PWA Install Button Elementor widget.
  • A WordPress Custom Link with the CSS class listeo-pwa-install.

The PWA Settings page also provides a downloadable QR code that opens the public installation page. On iPhone and iPad, visitors install the app through Share → Add to Home Screen.


Offline bookings and QR tickets

A booking is saved automatically when an authorized user opens its details while online.

  • Guests get the same booking information available in My Bookings.
  • Owners and team members get the information available in Bookings.
  • Users can search, open and remove local copies from the Saved page.
  • The per-device limit is 25 by default. Set it to 0 to remove the count limit. Browser storage limits still apply.

Eligible guest tickets can include the issued ticket code and QR image. Users can open a large ticket view, switch between tickets, share or download the ticket image, add the booking to a calendar with an .ics file and share the public listing page.

Offline copies are read-only and show the last saved information. Ticket admission is still verified online by the organizer. Local copies are removed after a detected sign-out or account change, or when the user clears browser data.


Settings reference

  • App name, icon and colors

  • Install suggestion

  • Offline data and app navigation

  • Analytics and launch attribution


Push notifications

Listeo PWA uses the existing Web Push feature in Listeo Notifications. You do not need separate push credentials. Each visitor must allow notifications and subscribe on their device. On iPhone and iPad, they subscribe from inside the installed app.


Troubleshooting

  • PWA Settings is missing

  • The app cannot be installed

  • It works for administrators but not on a phone

  • The installation suggestion does not appear

  • A booking or ticket is missing offline


Listeo MCP

Purethemes MCP lets you manage WordPress from ChatGPT or Claude. The assistant can use only the tools you enable, and every action still follows the connected user’s WordPress permissions.

What can Purethemes MCP do? Basically everything.

  • Build Elementor pages and edit individual widget settings.
  • Configure Listeo search forms and add or remove search filters.
  • Add or remove fields in Listeo Editor submission forms.
  • Create and configure listing types, booking modes, and taxonomies.
  • Create, edit, publish, approve, and renew Listeo listings.
  • Manage bookings, availability, time slots, payments, cancellations, and rescheduling.
  • Create and modify WordPress pages, posts, menus, metadata, and media.
  • Manage WooCommerce orders, coupons, order notes, and refunds.
  • Audit listings and site configuration for missing content or setup issues.
  • Control every capability with permissions, activity logs, and supported undo.

Example requests

  • Listings & moderation
    • “Approve the listings waiting for review, but reject any without photos.”
    • “Renew every featured listing that expires this week for another 30 days.”
    • “Unpublish the ‘Old Diner’ listing and set its rejection reason to ‘permanently closed’.”
    • “Create a ‘Downtown Coworking’ listing in the Offices category with these details and put it live.”
  • Bookings & availability
    • “A guest just called — book the Beach Villa for next Fri–Sun for John ([email protected]).”
    • “Move tomorrow’s 2 PM appointment at the Barber Shop to Thursday and email the client.”
    • “Block the Mountain Cabin for all of August, and mark last week’s pending booking as paid.”
    • “Show this month’s reservations and revenue by status.”
  • Directory setup
    • “Add a ‘Pet friendly’ feature to Restaurants and include it in the search form.”
    • “Create a new ‘Event Space’ listing type with a per-day booking mode.”
    • “Add an ‘Instagram’ custom field to the submit form for the Shops type.”
  • Health checks
    • “Which listings are missing a cover image, opening hours, or a map location?”
    • “List everything expiring in the next 7 days.”


Before you connect

– Your site needs a public HTTPS address and pretty permalinks.
– The AI service must support custom remote MCP connections.
– A WordPress administrator must approve the connection.

Local, VPN-only, and firewalled sites cannot be reached by cloud-based AI services. Connector availability can also depend on the service plan or workspace.


Connect your assistant

1. Download Purethemes MCP from Customer Portal → 
2. On your WordPress site, go to Plugins → Add New → Upload, select the zip with plugin.
2. After activation navigate to Listeo Core → MCP Server
3. Choose an access profile and save.
4. Copy the address shown for your assistant.

ChatGPT

1. Go to Settings → Security and Login and enable Developer Mode.
2. Go to Plugins → Add Plugin and paste the ChatGPT address.


Claude

1. Go to Settings → Connectors.
2. Click Add → Add Custom Connector and paste the Claude address.

 

ChatGPT and Claude use different MCP addresses. Copy the URL from the matching provider card. Then sign in to WordPress and approve access.

In both cases it will ask you to authenticate and allow the access to your site, you can define the access profile and what tools the MCP will be able to control

 


Choose an access profile

– Read only: Inspect listings, bookings, WordPress content, users and store data. Cannot change the site.
– Daily Operations: Manage listings and bookings. Cannot refund orders, change site structure or manage user accounts.
– Content & Setup: Daily operations plus WordPress content, menus, Elementor and Listeo configuration. No refunds or user management.
– Full access (YOLO mode): Everything is switched on: listings, bookings, WordPress content, users, WooCommerce refunds and permanent deletions. Capability checks and the activity log still apply.
– Custom permissions: Select permissions individually.

mcp permissions for listeo


Changing permissions in MCPsettings might require deleting app/connection from ChatGPT/Claude and adding it again.


Recent activity

Open Activity Logs to view connection controls and the audit log.

– Activity loads only when the panel is opened, 20 events at a time.
– Metadata is kept for up to 90 days.
– Message bodies, argument values, and tool results are never logged.
– Revoke all connections disconnects every authorized AI app.


If the connection fails

1. Click Re-run beside the connection status and follow the displayed fix.
2. Check HTTPS and pretty permalinks.
3. Allow /.well-known/* and /wp-json/puriochat-mcp/* through your server, security plugin, and CDN.
4. If you use Cloudflare, make sure Claude-User is not blocked under Manage AI bot access.
5. Save the MCP settings and reconnect the assistant.

Note: Listeo MCP is a separated plugin that is specifically created for Listeo while MCP available in PurioChat Pro is for general use and lacks deep integration with Listeo theme.

 

Listeo Team – co-authors functionality

The Team feature lets listing owners invite employees without sharing an account. Owners choose which listings each employee can access and what they can do.

What the Team Feature Does

Owners can give employees one or more permissions:

  • Edit listings: Edit assigned listings.
  • Manage bookings: View and manage bookings for assigned listings.
  • Messages: Reply to messages linked to assigned listings.

Employees use their own accounts. They cannot see the owner’s other listings, bookings, messages, wallet, subscriptions, or account settings.

Choose What Employees Can Edit

For employees with the Edit listings permission, you can allow access to specific areas:

  • Content & Media
  • Location
  • Pricing & Coupons
  • Booking Settings
  • Availability Calendar
  • Opening Hours

All areas are selected by default for new team members.

Listing and Resource Access

You can assign an employee to:

  • A whole listing: The employee can use their granted permissions for that listing.
  • A specific resource: The employee can manage only selected rooms, staff, tables, vehicles, or other resources.

Resource access requires the Listeo Booking Plus add-on. Without it, you can assign only whole listings.


Requirements

  • Listeo Core 2.0.53 or newer
  • Listeo Booking Plus, only for resource access


Step 1: Enable the Team Feature

Go to WP Admin → Listeo Core → General → Team.

  1. Turn on Enable Team feature.
  2. Set the Team Page. Click Create page, or select a page that contains [listeo_team].
  3. Set the Team Invitation Page. Click Create page, or select a page that contains [listeo_team_invite].
  4. Set Maximum team members. Use 0 for no limit. Pending and active members both count toward the limit.
  5. Set Invitation expiry. The default is 7 days.
  6. Choose whether employees may unpublish or delete assigned listings. Both options are off by default.
  7. Click Save Settings.

After you assign a Team or Team Invitation page, the Create page button changes to an Edit page link.

Team settings in Listeo Core

If the Team feature is enabled but no Team Page is set, WordPress shows an admin warning. Create or select a page with [listeo_team] to fix it.

Team Emails

Go to WP Admin → Listeo Core → Emails → Team Emails to edit these messages:

  • Team Invitation Email: Sent to the invited person. Available tags: {owner_name}, {site_name}, {invite_link}, {expiry_date}.
  • Team Invitation Response Email: Sent to the owner when someone accepts, declines, or leaves. Available tags: {employee_name}, {owner_name}, {site_name}, {response}.
  • Team Member Removed Email: Sent to an employee after access is revoked. Available tags: {owner_name}, {site_name}.

Team email settings


Step 2: Invite an Employee

Open the Team page in the owner dashboard.

  1. Click Invite New Member.
  2. Enter the employee’s email address.
  3. Select at least one permission: Edit listings, Manage bookings, or Messages.
  4. If they can edit listings, select the areas they may change.
  5. Select the listings they may access.
  6. If Listeo Booking Plus is active, you can assign specific resources instead.
  7. Click Send Invitation.

You can invite someone before you have listings and assign listings later. Sites with many listings use a search field to make selection easier.

Invite New Member form

You cannot invite yourself. For a pending invitation, use Resend Invite. If the person is already an active member, edit their access instead.


Step 3: Accept the Invitation

The process depends on whether the invited person already has an account:

  • Existing user: They sign in, open the Team page, and select Accept or Decline.
  • New user: They open the Team Invitation page and register. Their email is already filled in and cannot be changed. Selecting Register & Join Team creates the account and activates access.

Team invitation registration page

Invitation Statuses

Status Meaning
Pending Sent but not answered
Active Accepted and ready to use
Declined Declined by the invited person
Revoked Removed by the owner, or the employee left
Expired The pending invitation is too old


After an Employee Joins

What Owners Can Do

The Team page shows each employee’s status, permissions, assigned listings or resources, and invitation date. Owners can:

  • Edit permissions and assignments.
  • Resend Invite for pending or declined invitations.
  • Revoke access for pending or active members.

Team management page

What Employees See

The dashboard shows only the pages allowed by their permissions:

  • My Listings: Requires Edit listings.
  • Bookings: Requires Manage bookings.
  • Messages: Requires Messages.
  • My Teams: Shows their team memberships and includes a Leave Team action.

Owner tools such as Add Listing, Coupons, Ad Campaigns, Wallet, Statistics, and Subscriptions stay hidden. Dedicated employee accounts also do not see Reviews or Bookmarks. Existing owner or guest accounts keep those menu items.

Employees only see messages linked to their assigned listings. Direct messages to the owner are private.


Resource Access with Listeo Booking Plus

This section applies only when Listeo Booking Plus is active.

Resource access lets an employee manage selected rooms, staff, tables, vehicles, or other resources without access to the full listing.

The employee must also have the Edit listings permission. Without it, the resource assignment will not work.

A resource employee can:

  • Edit assigned resources within the allowed areas.
  • Pause or resume assigned resources.
  • Manage bookings for assigned resources.

They cannot create, delete, or reassign resources. Listing owners and admins keep those controls. An employee with whole-listing access may create or duplicate resources, but cannot delete or reassign them.

Employees open assigned resources from the Resources dashboard page. Make sure Listeo Core → Pages → Manage Resources Page points to a published page containing [lbp_manage_resources].


FAQ

  • Can employees see the owner's other content?

  • Can I limit how many employees an owner can invite?

  • Can an employee unpublish or delete a listing?

  • What happens when I revoke an employee?

  • Can an employee manage resource bookings without the Manage bookings permission?


Troubleshooting

  • The invitation link is invalid, expired, or already used

  • A new employee is asked to sign in with a different account

  • An employee cannot see a conversation

  • An employee cannot unpublish or delete a listing

  • You have reached the maximum number of team members

  • A resource-only employee cannot open their resource

  • Please wait a moment before resending this invitation

  • You have sent too many invitations. Please try again later.


For Developers

Team / Employees includes a permission API, filters, and actions for access checks, editable areas, resource assignments, and revoking access. See the Developer Hooks Reference for the full list.

Migrate to Listeo from HivePress, Directorist and ListingPro

Switching from HivePress, ListingPro or Directorist? Bring your data with you!
The free Listeo Migration migrates your listings, categories, custom fields, images, reviews and users to Listeo — no CSV exports, no manual re-entry.

Moving a directory between platforms usually means rebuilding every listing by hand. Not anymore. The Listeo Migration plugin automates the entire transformation directly in your WordPress database, in one guided process. Type mapping, attribute mapping and a read-only preview let you verify everything before a single row is changed.

If you’ve been running your directory on HivePress, ListingPro or Directorist and want Listeo’s built-in bookings, marketplace and AI-powered search (see why users switch from HivePress →), this guide walks you through the whole migration step by step.

Listeo Migration plugin settings

✅ FREE add-on converts directly in your database (NO export/import round-trip):
1. Listings (published, draft, pending & private — titles, descriptions, slugs, authors)
2. Categories (mirrored to Listeo, missing ones created automatically)
3. Custom Fields / Attributes (mapped to existing Listeo fields, new fields or amenities)
4. Geolocation (Latitude & Longitude for Map Pin + Address)
5. Gallery Images (featured image kept separate — no duplicated covers)
6. Reviews & Star Ratings (with recalculated average rating per listing)
7. Listing Types (service / rental / event / classifieds — manual map or auto-detect)
8. User Roles (listing authors get Listeo’s “owner” role for dashboard access)
9. Featured & Verified badges
10. Contact Details (phone, website, email & socials pre-mapped out of the box)

💡 Smart mapping included: price ranges like “$25–$40” are split automatically into Listeo’s min/max price fields, URLs and emails are sanitized, and only approved reviews are counted so pending or spam reviews won’t distort your ratings.

🔁 Safe to re-run – converted listings are flagged and skipped on subsequent runs, so an interrupted conversion can simply be restarted.


⚠️ Back up your database before converting. The migration modifies your data in place — a full backup takes minutes and makes the whole process risk-free. Also make sure the Listeo Core plugin is installed and activated first: the converter needs Listeo’s categories, features and the “owner” role to exist, and will warn you if they don’t.



Installation & How to use?
  1. Download .zip https://purethemes.net/listeo-migration.zip with Listeo Migration plugin
  2. Upload listeo-migration.zip in WP Dashboard → Plugins → Add New and install & activate. Do this on the site that still contains your HivePress, ListingPro or Directorist data — you switch the theme after conversion, not before.
  3. Go to Tools → Listeo Migration. The converter automatically scans your site and shows how many HivePress, ListingPro or Directorist listings were found and how many listing authors still need the Listeo owner role. If no data is detected, there’s nothing to migrate. 🙂
  4. Preview before you convert. Click “Preview 5 Listings” to see a read-only, field-by-field breakdown — each field, its current value, and the Listeo field it maps to. Nothing is written to the database at this stage.
  5. Configure the mapping. Assign a Listeo listing type (service, rental, event or classifieds) to each HivePress, ListingPro or Directorist category — or leave it on Auto-detect (a “Hotels” category becomes a rental, “Workshops” becomes an event, and so on). Then review the attribute table and decide where each custom field should go:
    – map it to an existing Listeo field,
    – create a brand-new custom field (added automatically to Listeo’s Forms & Fields Editor),
    – merge it into the amenities/features taxonomy,
    – or skip it entirely.Common attributes — phone, website, email, socials, price — are pre-mapped out of the box. You can also enable stripping of Gutenberg block markup from descriptions, since Listeo uses the classic editor for listings. Hit Save Settings when you’re happy with the mapping.
  6. Migrate user roles. Click “Migrate Roles” to grant the Listeo owner role to every user who authored a listing, so your vendors can log into the Listeo dashboard right away. Existing accounts, passwords and profiles are untouched.
  7. Hit “Start Conversion” and let the magic happen. Listings are processed in small batches with a live progress bar and per-listing log, so even directories with thousands of listings convert reliably without server timeouts. When it finishes, a summary shows how many listings were converted, skipped or had errors — with direct edit links for anything that needs attention.
  8. Switch to the Listeo theme. Activate Listeo, run the setup wizard and open a few migrated listings to verify categories, map pins, galleries and reviews. That’s it — your directory is now running on Listeo with bookings, listing packages and all other built-in features →


FAQ


  • Is the Listeo Migration free?


  • Will I lose my reviews and ratings?


  • Do my users need to re-register?


  • What happens to my custom attributes?


  • Can I re-run the conversion?


  • Do I need WP All Import or a CSV export?


  • What about my listing photos?




Markdown for AI Agents

This plugin serves a clean Markdown version of your public pages to AI agents, crawlers, and any tool that would rather read structured text than a full HTML page.

Markdown is easier for AI to work with: it keeps your headings, lists, and links but drops the navigation, scripts, styles, and forms. Less noise, and the agent understands the page more reliably.

Note The plugin requires Listeo Core. It doesn’t touch Cloudflare – no Worker, no paid plan, and no custom server config on a standard WordPress host.


Is it better than llms.txt?

Certainly. There is still no convincing evidence that llms.txt works. Ahrefs’ analysis of 137,000 websites found that 97% of llms.txt files were never accessed.

Serving Markdown to AI agents via HTTP content negotiation (Accept: text/markdown) is a different approach. It’s already supported by major infrastructure like Cloudflare, and AI search agents such as Claude/ChatGPT/Perplexity request Markdown directly when available. More at The Cloudflare Blog: Introducing Markdown for Agents

On our own site we use the same solutions and we see the Markdown versions being requested hundreds of times per day.


Install and preload the cache

  1. Download plugin from Customer Portal →
  2. In the WordPress admin, go to Plugins > Add New and upload the plugin ZIP.
  3. Activate Listeo Markdown for Agents (Listeo Core needs to be active first).
  4. Open Listeo Core > Listeo Markdown.
  5. Go to the Preload Cache tab and click Start / preload missing.

Preloading runs in small background batches via Action Scheduler (or WP-Cron if that’s not available). It’s worth doing right after activation, especially on directories with hundreds or thousands of listings.

The same screen has a content browser where you can search and filter by post type or cache status to see what’s cached, generated on demand, or excluded. It loads a few items at a time so it stays light on shared hosting.

Plugin “Preload Cache” Page

Tip Use Rebuild all after a big site-wide design or visibility change. Everyday edits are handled for you and don’t need a rebuild.


How it works

Every supported public page gets a Markdown twin at the same URL with .md on the end:

https://example.com/about/
https://example.com/about.md

https://example.com/listing/example-listing/
https://example.com/listing/example-listing.md

https://example.com/product/example-product/
https://example.com/product/example-product.md

Agents can also just ask the normal page URL for Markdown using a standard HTTP header:

curl https://example.com/about/ \
  -H "Accept: text/markdown"

Either way the response comes back as Content-Type: text/markdown. The .md URLs are cacheable by browsers and CDNs; responses negotiated through the HTML URL are marked private and no-store so they never mix with your regular page cache.


Disk cache and automatic updates

Generated documents live in a protected, non-public cache inside your WordPress uploads folder.

  • If a cached file exists, the plugin serves it straight from disk.
  • If it’s missing, WordPress builds the Markdown on the spot, returns it, and saves it for next time.
  • When a post, page, listing, product, testimonial, taxonomy, or relevant public field changes, its Markdown is refreshed automatically.

There’s no “pending” page and no Worker in the way. The very first request can be a little slower than a cache hit, but the agent still gets the finished document in that same request.


Supported content

  • WordPress posts and pages, including Gutenberg content.
  • Published Elementor pages rendered through the normal public pipeline.
  • Listeo listings — details, taxonomies, opening hours, images, and contact fields your visibility settings allow.
  • WooCommerce products — descriptions, price, availability, attributes, categories, and images.
  • Testimonials.

Only published, publicly viewable, password-free content qualifies, and common SEO noindex settings are respected. Cart, checkout, My Account, shop archives, attachments, Elementor templates, and private Listeo data are all left out.


Like Cloudflare Markdown for Agents – minus the Worker

The idea mirrors Cloudflare Markdown for Agents: send Accept: text/markdown, get structured Markdown back instead of HTML.

The difference is where the work happens. Cloudflare converts HTML to Markdown on its network for enabled zones. This plugin does it inside WordPress, so it understands Listeo and WooCommerce content directly and caches the result on your own disk. It works with or without Cloudflare, and there’s no Worker to deploy or maintain.